package com.deuwise.system.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.deuwise.common.base.BaseCoreServiceImpl;
import com.deuwise.common.exception.DeuWiseException;
import com.deuwise.common.utils.Base64Utils;
import com.deuwise.common.utils.EnumErrorCode;

import com.deuwise.common.utils.SpringContextHolder;
import com.deuwise.config.CacheConfiguration;
import com.deuwise.config.JWTConfigProperties;
import com.deuwise.config.oauth2.JWTUtil;
import com.deuwise.system.entity.SysUser;
import com.deuwise.system.entity.TokenVO;
import com.deuwise.system.mapper.SysUserMapper;
import com.deuwise.system.service.SysUserRoleService;
import com.deuwise.system.service.SysUserService;
import com.github.kevinsawicki.http.HttpRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *  接口用户实现类
 *@author deuwise
 *@date 2018-11-06 14:15:04
 **/
@Service
public class SysUserServiceImpl extends BaseCoreServiceImpl<SysUserMapper, SysUser> implements SysUserService {
    private static class Holder {
        static final JWTConfigProperties JWT_CONFIG = SpringContextHolder.getBean(JWTConfigProperties.class);
        static final Cache LOGOUT_TOKENS = CacheConfiguration.dynaConfigCache(JWT_CONFIG.getExpireTokenKeyPrefix(), JWT_CONFIG
                .getRefreshTokenExpire());
    }

    Logger logger= LoggerFactory.getLogger(SysUserServiceImpl.class);

    @Override
    public SysUser queryByUserName(String username) {
        Wrapper<SysUser> wrapper=new EntityWrapper<>();
        wrapper.eq("user_name",username);
        return this.selectOne(wrapper);
    }

    @Override
    public Integer queryByUserName(String username, SysUser user) {
        Wrapper<SysUser> wrapper=new EntityWrapper<>();
        wrapper.eq("user_name",username);
        if(user!=null){
            wrapper.ne("id",user.getId());
        }
        return this.selectCount(wrapper);
    }

    @Override
    public TokenVO getToken(String uname, String passwd, String ...identities) {
        SysUser user = findOneByKv("user_name", uname);
        if (null == user || !user.getPassword().equals(passwd)) {
            throw new DeuWiseException(EnumErrorCode.apiAuthorizationLoginFailed.getCodeStr());
        }
        if(user.getStatus()!=1){
            throw new DeuWiseException(EnumErrorCode.statusNoOn.getCodeStr());
        }

        return createToken(user,identities);
    }

    @Override
    public TokenVO refreshToken(String uname, String refreshToken, String ...identities) {
        ensureAvailable(refreshToken, true);

        SysUser user = findOneByKv("user_name", uname);
        if(user == null){
            throw new DeuWiseException(EnumErrorCode.apiAuthorizationInvalid.getCodeStr());
        }

        return createToken(user,identities);
    }
    private TokenVO createToken(SysUser user, String ...identities) {
        TokenVO vo = new TokenVO();
        String token        = JWTUtil.sign(user.getId()+"", user.getUsername() + user.getPassword(), Holder.JWT_CONFIG.getExpireTime(),identities);
        String refreshToken = JWTUtil.sign(user.getId()+"", user.getUsername() + user.getPassword(), Holder.JWT_CONFIG.getRefreshTokenExpire(), true,identities);
        vo.setToken(token);
        vo.setRefreshToken(refreshToken);
        vo.setTokenExpire(Holder.JWT_CONFIG.getExpireTime());
        vo.setRefreshTokenExpire(Holder.JWT_CONFIG.getRefreshTokenExpire());
        return vo;
    }
    @Override
    public void verifyToken(String token, boolean isRefresh,String ...identities) {
        ensureAvailable(token, isRefresh,identities);
    }

    @Override
    public void logoutToken(String token, String refreshToken) {
        Holder.LOGOUT_TOKENS.putIfAbsent(token, null);
        Holder.LOGOUT_TOKENS.putIfAbsent(refreshToken, null);
    }

    @Override
    public boolean updatePassword(String userId, String password, String newPassword) {
        SysUser userEntity = new SysUser();
        userEntity.setPassword(newPassword);
        return this.update(userEntity,
                new EntityWrapper<SysUser>().eq("id", userId).eq("password", password));
    }

    @Override
    public List<String> queryAllMenuId(String userId,String appId) {
        return baseMapper.queryAllMenuId(userId,appId);
    }

    @Autowired
    SysUserRoleService sysUserRoleService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(SysUser sysUser) {

        sysUser.setPassword(Base64Utils.base64Encrypt(sysUser.getPassword()));
        boolean result= this.insert(sysUser);

        //检查角色是否越权
       // checkRole(user);

        //保存用户与角色关系

        sysUserRoleService.saveOrUpdate(sysUser.getId(), sysUser.getRoleIdList());
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysUser user) {
        boolean result= this.updateById(user);

        //检查角色是否越权
        // checkRole(user);

        //保存用户与角色关系

        sysUserRoleService.saveOrUpdate(user.getId(), user.getRoleIdList());
    }
    @Value("${bootsystem.sso}")
    private Boolean ssoStatus;

    @Value("${bootsystem.systemUrl}")
    private String systemUrl;

    private void ensureAvailable(String token, boolean isRefreshToken,String ...identities) {
        if(StringUtils.isBlank(token)){
            throw new DeuWiseException(EnumErrorCode.apiAuthorizationInvalid.getCodeStr());
        }
        String userId = JWTUtil.getUserId(token);
        String userAgent= JWTUtil.getUserAgent(token);
        if(StringUtils.isBlank(userId)){
            throw new DeuWiseException(EnumErrorCode.apiAuthorizationInvalid.getCodeStr());
        }
        if(Holder.LOGOUT_TOKENS.get(token) != null){
            throw new AuthenticationException(EnumErrorCode.apiAuthorizationLoggedout.getMsg());
        }
        SysUser userDO =null;
        if(ssoStatus){
            Map<String,Object> map=new HashMap<>();
            map.put("Authorization",token);
            HttpRequest httpRequest=HttpRequest.get(systemUrl+"/api/SysUser/"+userId+"?token="+token,map,false);
            httpRequest.header("User-Agent",userAgent);
            try{
                boolean result=  httpRequest.code()==200;
                if(result){
                  JSONObject jsonObject= JSONObject.parseObject(httpRequest.body());
                  if(jsonObject.get("code")!=null&&jsonObject.getInteger("code")==0) {
                      userDO = jsonObject.getJSONObject("user").toJavaObject(SysUser.class);
                  }
                }
            }catch (Exception ex){
                throw new DeuWiseException(EnumErrorCode.apiAuthorizationInvalid.getCodeStr());
            }
        }else {
             userDO = selectById(userId);
        }

        if(userDO == null){
            throw new DeuWiseException(EnumErrorCode.apiAuthorizationInvalid.getCodeStr());
        }

        if(isRefreshToken){
            JWTUtil.verify(token, userDO.getId() + "", userDO.getUsername() + userDO.getPassword(), true,identities);
        }else{
            JWTUtil.verify(token, userDO.getId() + "", userDO.getUsername() + userDO.getPassword(),identities);
        }
    }
}